package com.hmall.search.service.serviceImpl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.hmall.dto.PageDTO;
import com.hmall.dto.RequestParams;
import com.hmall.pojo.Item;
import com.hmall.pojo.ItemDoc;
import com.hmall.search.mapper.SearchMapper;
import com.hmall.search.service.SearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;


import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class SearchServiceImpl extends ServiceImpl<SearchMapper, Item> implements SearchService {
    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageDTO<ItemDoc> search(RequestParams requestParam) throws IOException {
        log.info("............");
        //拿到请求参数的值
        String key = requestParam.getKey();//搜索的字段
        Integer page = requestParam.getPage();//搜索的开始页数
        Integer size = requestParam.getSize();//每页的最多数据
        String sortBy = requestParam.getSortBy();//排序规则
        String brand = requestParam.getBrand();//品牌
        String category = requestParam.getCategory();// 分类
        Integer minPrice = requestParam.getMinPrice();//价格范围 最小值
        Integer maxPrice = requestParam.getMaxPrice();//价格范围 最大值
        //构建返回对象
        PageDTO<ItemDoc> pageDTO = new PageDTO();
        //多个请求限定用BoolQueryBuilder
        BoolQueryBuilder bo = QueryBuilders.boolQuery();
        //字段搜索
        //1.1构建search请求
        SearchRequest request = new SearchRequest("item");
        //分页
        request.source().from((page - 1) * size).size(size);
        //1.2判断key是否为空 作出不同判断
        if (!StringUtils.isEmpty(key)) {
            bo.must(QueryBuilders.matchQuery("all", key));
        } else {
            bo.must(QueryBuilders.matchAllQuery());
        }
        //1.4条件过滤 -- 分类 品牌 价格过滤
        if (!StringUtils.isEmpty(brand)) {
            if (brand.equals("oppo")) {
                bo.must(QueryBuilders.termQuery("brand", brand.toUpperCase()));
            } else {
                bo.must(QueryBuilders.termQuery("brand", brand));
            }
        }

        if (!StringUtils.isEmpty(category)) {
            bo.must(QueryBuilders.termQuery("category", category));
        }

        if (!StringUtils.isEmpty(minPrice)) {
            bo.filter(QueryBuilders.rangeQuery("price").gte(minPrice * 100));
        }
        if (!StringUtils.isEmpty(maxPrice)) {
            bo.filter(QueryBuilders.rangeQuery("price").lte(maxPrice * 100));
        }
        // 1.5 高亮
        request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
        //1.6 升序价格排序
        if (!StringUtils.isEmpty(sortBy)) {
            if (sortBy.equals("price")) {
                request.source().sort("price", SortOrder.ASC);
            }
            if (sortBy.equals("sold")) {
                request.source().sort("sold", SortOrder.DESC);
            }
        }
        //1.7 竞价排名 -广告
        FunctionScoreQueryBuilder fuck = QueryBuilders.functionScoreQuery(bo,
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD", true),
                                ScoreFunctionBuilders.weightFactorFunction(10))
                });
        //1.8发送请求
        request.source().query(fuck);
        //2.1返回结果
        SearchResponse repose = client.search(request, RequestOptions.DEFAULT);
        //2.2接收返回结果
        long total = repose.getHits().getTotalHits().value;
        pageDTO.setTotal(total);

        //2.3构建返回集合
        List<ItemDoc> list = new ArrayList<>();
        //2.4解析返回结果
        SearchHit[] item = repose.getHits().getHits();
        for (SearchHit hit : item) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSON.parseObject(json, ItemDoc.class);
            list.add(itemDoc);
            //2.5给结果的高亮字段重新赋值
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.size() != 0) {
                HighlightField highlightField = highlightFields.get("name");
                String name = highlightField.getFragments()[0].string();
                itemDoc.setName(name);
            }
        }
        pageDTO.setList(list);
        return pageDTO;
    }

    /**
     * 实时更新es
     *
     * @param item
     */
    @Override
    public void updateES(Item item) throws IOException {
        Integer status = item.getStatus();
        //判断状态 上架状态就加入索引库文档
        if (status == 1) {
            ItemDoc itemDoc = new ItemDoc(item);
            String json = JSON.toJSONString(itemDoc);
            IndexRequest request = new IndexRequest("item").id(itemDoc.getId().toString());
            request.source(json, XContentType.JSON);
            client.index(request, RequestOptions.DEFAULT);
        } else {
            log.info("下架操作：{}", item);
            //下架就删除
            DeleteRequest request = new DeleteRequest("item", item.getId().toString());
            client.delete(request, RequestOptions.DEFAULT);
        }
    }
}
